package com.chenfan.mcn.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.common.utils.DateUtils;
import com.chenfan.mcn.clients.baseinfo.BaseCustomer;
import com.chenfan.mcn.clients.baseinfo.BaseInfoClient;
import com.chenfan.mcn.clients.finance.ClearData4ExecuteOrderVo;
import com.chenfan.mcn.clients.finance.FinanceClient;
import com.chenfan.mcn.clients.privilege.DepartmentVO;
import com.chenfan.mcn.clients.privilege.PrivilegeClient;
import com.chenfan.mcn.clients.privilege.SDepartment;
import com.chenfan.mcn.clients.privilege.SUser;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.BillCodeCst;
import com.chenfan.mcn.constant.DictTypeCst;
import com.chenfan.mcn.constant.McnConstant;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.DeleteEnum;
import com.chenfan.mcn.enums.ExcutionApprovalStatusEnum;
import com.chenfan.mcn.enums.IncomeContractTypeEnum;
import com.chenfan.mcn.enums.PaybackStatusEnum;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.component.CodeGenerateHelper;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.model.common.PageInfo;
import com.chenfan.mcn.model.dto.BusinessCommissionUpdateDTO;
import com.chenfan.mcn.model.dto.ExcutionOrderSearchDTO;
import com.chenfan.mcn.model.dto.IncomeContractSearchDTO;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.rule.BusinessCommissionRuleContext;
import com.chenfan.mcn.rule.BusinessCommissionV1Rule;
import com.chenfan.mcn.rule.BusinessCommissionV2Rule;
import com.chenfan.mcn.extension.rule.ComputableRuleEngine;
import com.chenfan.mcn.service.*;
import com.chenfan.mcn.utils.BusinessAssert;
import com.chenfan.mcn.utils.CommonUtil;
import com.chenfan.mcn.utils.DateUtil;
import com.chenfan.mcn.utils.NoRepeatableArrayList;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 商务提成明细临时表 服务实现类
 * </p>
 *
 * @author lizhejin
 * @since 2021-06-07
 */

@RefreshScope
@Service
@Slf4j
public class BusinessCommissionDetailTemporaryServiceImpl extends ServiceImpl<BusinessCommissionDetailTemporaryMapper, BusinessCommissionDetailTemporary> implements BusinessCommissionDetailTemporaryService {

    @Autowired
    private BusinessCommissionDetailTemporaryMapper temporaryMapper;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private CustomerTargetMapper customerTargetMapper;

    @Autowired
    private DepartmentTargetMapper departmentTargetMapper;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private BusinessCommissionMapper businessCommissionMapper;

    @Autowired
    private BusinessCommissionService businessCommissionService;

    @Autowired
    private BusinessCommissionDetailMapper businessCommissionDetailMapper;

    @Autowired
    private BusinessCommissionReturnMapper bcReturnMapper;

    @Autowired
    private ContractExcutionOrderMapper contractExcutionOrderMapper;

    @Autowired
    private FinanceClient financeClient;

    @Autowired
    private StarPlatformInfoService starPlatformInfoService;

    @Autowired
    private ContractExcutionOrderService contractExcutionOrderService;

    @Autowired
    private BrandInfoService brandInfoService;

    @Value("${bc.return.earliest-start-date : 2021-09-01 00:00:00}")
    private String earliestStartDateStr;

    /**
     * 添加合同（全选并确认）
     *
     * @param addContract {@link AddContract}
     * @return {@link String}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addContract(AddContract addContract) {
        String temporaryCode = temporaryCode(addContract.getTemporaryCode());
        if (Objects.isNull(addContract.getId())) {
            add(addContract.getExcuteIds(), temporaryCode);
            return temporaryCode;
        } else {
            BusinessCommission businessCommission = businessCommissionMapper.selectById(addContract.getId());
            getIncomeCodesV2(businessCommission, addContract.getExcuteIds());
            //获取关联的执行单并更新商务结算状态为结算中
            contractExcutionOrderService.updateBusinessCommissionSettleStatusByIds(addContract.getExcuteIds(), NumberCst.ZERO, NumberCst.ONE);
            return null;
        }

    }

    @SneakyThrows
    public void add(List<Long> excuteIds, String temporaryCode) {
        List<BusinessCommissionDetailTemporary> temporaries = this.baseMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class)
                .in(BusinessCommissionDetailTemporary::getExcuteId, excuteIds)
                .eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE));
        List<Long> finalExcuteIds;
        if (Objects.nonNull(temporaries)) {
            List<Long> existExcuteIds = temporaries.stream().map(BusinessCommissionDetailTemporary::getExcuteId).distinct().collect(Collectors.toList());
            finalExcuteIds = excuteIds.stream().filter(x -> !existExcuteIds.contains(x)).collect(Collectors.toList());
        } else {
            finalExcuteIds = excuteIds;
        }
        BusinessAssert.notEmpty(finalExcuteIds, McnErrorCode.EXCUTE_ORDER_CANNOT_BE_REPEATED);
        //根据执行单ID获取对应的合同号
        List<BusinessCommissionDetailTemporary> insertList = this.executeNewBusinessCommissionRule(temporaryCode, finalExcuteIds);
        if (CollectionUtils.isNotEmpty(insertList)) {
            this.baseMapper.insertBatch(insertList);
        }
    }

    /**
     * 批量删除
     *
     * @param ids {@link List<Long>}
     * @return {@link Boolean}
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean batchDelete(List<Long> ids) {
        List<BusinessCommissionDetailTemporary> oldList = this.baseMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class)
                .in(BusinessCommissionDetailTemporary::getId, ids).eq(BusinessCommissionDetailTemporary::getIsDelete, NumberCst.ZERO));
        if(CollectionUtils.isEmpty(oldList)) {
            return true;
        }
        List<Long> oldExcuteIds = oldList.stream().map(x -> x.getExcuteId()).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        String temporaryCode = oldList.stream().map(BusinessCommissionDetailTemporary::getTemporaryCode).filter(Objects::nonNull).findFirst().orElse(null);
        oldList.forEach(x -> x.setIsDelete(DeleteEnum.TRUE.getValue()));
        boolean result = this.updateBatchById(oldList);
        ///获取关联的执行单并更新商务结算状态为待结算
        List<BusinessCommissionDetailTemporary> newList = this.baseMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class)
                .select(BusinessCommissionDetailTemporary::getExcuteId)
                .eq(BusinessCommissionDetailTemporary::getTemporaryCode, temporaryCode)
                .in(BusinessCommissionDetailTemporary::getExcuteId, oldExcuteIds)
                .eq(BusinessCommissionDetailTemporary::getIsDelete, NumberCst.ZERO));
        List<Long> newExcuteIds = CommonUtil.defaultList(newList).stream().map(x -> x.getExcuteId()).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<Long> deleteExcuteIds = oldExcuteIds.stream().filter(e -> !newExcuteIds.contains(e)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(deleteExcuteIds)) {
            contractExcutionOrderService.updateBusinessCommissionSettleStatusByIds(deleteExcuteIds, NumberCst.ONE, NumberCst.ZERO);
        }
        return result;
    }

    /**
     * 编辑列表
     *
     * @param dto 传参
     * @return {@link Integer}
     */
    @SneakyThrows
    @Override
    public Integer edit(BusinessCommissionUpdateDTO dto) {
        List<Long> commissionIds = new ArrayList<>(Collections.singletonList(dto.getCommissionId()));
        commissionIds.add(dto.getDepartmentHeadId());
        List<SUser> sUsers = Objects.requireNonNull(privilegeClient.getUserByIds(commissionIds)).getObj();
        Map<Long, SUser> sUserMap = sUsers.stream().collect(Collectors.toMap(SUser::getUserId, sUser -> sUser));
        BusinessCommissionDetailTemporary temporary = temporaryMapper.selectById(dto.getId());
        //temporary.setGeneralPoints(BigDecimal.ZERO);
        temporary.setCommissionId(dto.getCommissionId());
        temporary.setDepartmentHeadId(dto.getDepartmentHeadId());
        //temporary.setDepartmentHeadCommissionPoint(BigDecimal.ZERO);
        //temporary.setTargetAchievementRate(BigDecimal.ZERO);
//        final Date v2StartDate = DateUtils.parseDate(earliestStartDateStr, McnConstant.LONG_DATE_FORMAT);
//        if (temporary.getCreateDate().before(v2StartDate)) {
//            //计算规则-V1
//            //个人提成=项目销售额*个人总提点*目标达成率
//            BigDecimal personalCommission = temporary.getProjectSales().multiply(temporary.getGeneralPoints())
//                    .multiply(temporary.getTargetAchievementRate()).setScale(2, BigDecimal.ROUND_HALF_UP);
//            temporary.setPersonalCommission(personalCommission);
//            //负责人提成=项目销售额*部门负责人提点
//            BigDecimal departmentHeadCommission = temporary.getProjectSales().multiply(temporary.getDepartmentHeadCommissionPoint())
//                    .setScale(2, BigDecimal.ROUND_HALF_UP);
//            temporary.setDepartmentHeadCommission(departmentHeadCommission);
//        } else {
//            //计算规则-V2
//            //个人提成=项目销售额*个人总提点
//            BigDecimal personalCommission = temporary.getProjectSales().multiply(temporary.getGeneralPoints())
//                    .setScale(2, BigDecimal.ROUND_HALF_UP);
//            temporary.setPersonalCommission(personalCommission);
//            //负责人提成=项目销售额*客户目标达成率*回款系数*部门负责人提点
//            BigDecimal departmentHeadCommission = temporary.getProjectSales().multiply(temporary.getDepartmentHeadCommissionPoint())
//                    .multiply(temporary.getTargetAchievementRate())
//                    .multiply(temporary.getReturnFactor()).setScale(2, BigDecimal.ROUND_HALF_UP);
//            temporary.setDepartmentHeadCommission(departmentHeadCommission);
//        }
        if (CommonUtil.containsKey(sUserMap, dto.getCommissionId())) {
            temporary.setCommissionName(sUserMap.get(dto.getCommissionId()).getUsername());
            temporary.setJobNumber(sUserMap.get(dto.getCommissionId()).getJobNumber());
        }
        if (CommonUtil.containsKey(sUserMap, dto.getDepartmentHeadId())) {
            temporary.setDepartmentHeadName(sUserMap.get(dto.getDepartmentHeadId()).getUsername());
            temporary.setDepartmentJobNumber(sUserMap.get(dto.getDepartmentHeadId()).getJobNumber());
        }
        temporary.setRemark(dto.getRemark());
        return this.baseMapper.updateById(temporary);
    }


    /**
     * 新建页提成明细列表
     *
     * @param page                分页
     * @param detailListSearchDTO 筛选条件
     * @return {@link BusinessCommissionDetailList}
     */
    @Override
    public BusinessCommissionDetailList detailList(McnPage<BusinessCommissionDetailTemporary> page, DetailListSearchDTO detailListSearchDTO) {
        BusinessCommissionDetailList businessCommissionDetailList = new BusinessCommissionDetailList();
        DateFormat dft = new SimpleDateFormat("yyyy-MM-dd");
        if (StringUtils.isNotBlank(detailListSearchDTO.getTemporaryCode())) {
            // McnPage<BusinessCommissionDetailTemporary> mcnPage = this.baseMapper.selectPage(page, Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class)
            //         .eq(BusinessCommissionDetailTemporary::getTemporaryCode, detailListSearchDTO.getTemporaryCode())
            //         .eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE)
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getCommissionName()), BusinessCommissionDetailTemporary::getCommissionName, detailListSearchDTO.getCommissionName())
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getDepartmentHeaderName()), BusinessCommissionDetailTemporary::getDepartmentHeadName, detailListSearchDTO.getDepartmentHeaderName())
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getContractCode()), BusinessCommissionDetailTemporary::getIncomeCode, detailListSearchDTO.getContractCode()));
            // PageInfo<BusinessCommissionDetailTemporary> personalCommissionPageInfo = PageInfo.toPageInfo(mcnPage, BusinessCommissionDetailTemporary.class);
            // Integer total = bcDetailTempMapper.selectCount(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class).eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE)
            //         .eq(BusinessCommissionDetailTemporary::getTemporaryCode, detailListSearchDTO.getTemporaryCode())
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getCommissionName()), BusinessCommissionDetailTemporary::getCommissionName, detailListSearchDTO.getCommissionName())
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getDepartmentHeaderName()), BusinessCommissionDetailTemporary::getDepartmentHeadName, detailListSearchDTO.getDepartmentHeaderName())
            //         .like(StringUtils.isNotBlank(detailListSearchDTO.getContractCode()), BusinessCommissionDetailTemporary::getIncomeCode, detailListSearchDTO.getContractCode()));
            Page<BusinessCommissionDetailVoV2> businessCommissionDetailV2List = this.baseMapper.selectListV2(page, detailListSearchDTO);
            PageInfo<BusinessCommissionDetailVoV2> personalCommissionPageInfo = PageInfo.toPageInfo(businessCommissionDetailV2List, BusinessCommissionDetailVoV2.class);
            convertType2Name(personalCommissionPageInfo);
            List<String> excuteCodes = personalCommissionPageInfo.getList().stream().map(BusinessCommissionDetailVoV2::getExcuteCode).collect(Collectors.toList());
            Map<String, ClearData4ExecuteOrderVo> clearData4ExecuteOrderMap = financeClient.clearData4ExecuteOrder(excuteCodes).getObj();
            List<Long> userIdList=new ArrayList<>();
            //设置提成人工号与业绩共享人工号
            List<Long> commissionIdList = personalCommissionPageInfo.getList().stream().map(BusinessCommissionDetailVoV2::getCommissionId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(commissionIdList)){
                userIdList.addAll(commissionIdList);
            }
            List<Long> performanceSharerIdList = personalCommissionPageInfo.getList().stream().map(BusinessCommissionDetailVoV2::getPerformanceSharerId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(performanceSharerIdList)) {
                userIdList.addAll(performanceSharerIdList);
            }
            List<Long> departmentHeadIdList = personalCommissionPageInfo.getList().stream().map(BusinessCommissionDetailVoV2::getDepartmentHeadId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(departmentHeadIdList)) {
                userIdList.addAll(departmentHeadIdList);
            }

            if (CollectionUtils.isNotEmpty(userIdList)) {
                List<SUser> sUserList = privilegeClient.getUserByIds(userIdList).getObj();
                Map<Long, String> sUserNameMap = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(sUserList),
                        () -> sUserList.stream().collect(Collectors.toMap(k -> k.getUserId(), v -> v.getJobNumber())), Collections.EMPTY_MAP);
                personalCommissionPageInfo.getList().forEach(x -> {
                    x.setJobNumber(sUserNameMap.get(x.getCommissionId()));
                    x.setPerformanceSharerNumber(sUserNameMap.get(x.getPerformanceSharerId()));
                    x.setDepartmentJobNumber(sUserNameMap.get(x.getDepartmentHeadId()));
                });
            }
            //设置部门名称
            List<Long> departmentIdList = personalCommissionPageInfo.getList().stream().map(BusinessCommissionDetailVoV2::getDepartmentId).filter(Objects::nonNull).distinct().collect(Collectors.toList());

            if(CollectionUtils.isNotEmpty(departmentIdList)) {
                Map<Long, SDepartment> sDepartmentMap = privilegeClient.getDepartmentByIds(departmentIdList).getObj();
                personalCommissionPageInfo.getList().forEach(x -> {
                    if (CommonUtil.containsKey(sDepartmentMap, x.getDepartmentId())) {
                        x.setDepartment(sDepartmentMap.get(x.getDepartmentId()).getDepartmentName());
                    }
                });
            }
            personalCommissionPageInfo.getList().forEach(x -> {
                x.setContractTypeName(IncomeContractTypeEnum.getContractTypeName(x.getContractType()));
                x.setContractPaybackStatusName(PaybackStatusEnum.getStatusName(x.getContractPaybackStatus()));
                x.setPaybackStatusName(PaybackStatusEnum.getStatusName(x.getPaybackStatus()));
                x.setApprovalStatusName(ExcutionApprovalStatusEnum.getStatusName(x.getApprovalStatus()));
                // 财务数据转换
                ClearData4ExecuteOrderVo clearData4ExecuteOrderVo = clearData4ExecuteOrderMap.get(x.getExcuteCode());
                if (Objects.nonNull(clearData4ExecuteOrderVo)) {
                    if (StringUtils.isNotBlank(clearData4ExecuteOrderVo.getArapDate())) {
                        String maxPaybackDate = getMaxClearDate(Arrays.asList(clearData4ExecuteOrderVo.getArapDate().split(",")));
                        x.setPaybackDate(maxPaybackDate);
                    }
                    if (StringUtils.isNotBlank(clearData4ExecuteOrderVo.getClearDate())) {
                        String maxClearDate = getMaxClearDate(Arrays.asList(clearData4ExecuteOrderVo.getClearDate().split(",")));
                        if (StringUtils.isNotBlank(maxClearDate) && StringUtils.isNotBlank(x.getRealPublishDate())) {
                            x.setPaidAccountPeriod(String.valueOf(DateUtil.getPhaseDifference(x.getRealPublishDate(), maxClearDate, dft)));
                        }
                        x.setClearDate(maxClearDate);
                    }
                }
            });
            personalCommissionPageInfo.setTotal(businessCommissionDetailV2List.getTotal());
            personalCommissionPageInfo.setPageNum(Long.valueOf(page.getPageNum()).intValue());
            personalCommissionPageInfo.setPageSize(Long.valueOf(page.getSize()).intValue());
            businessCommissionDetailList.setBusinessCommissionDetailV2List(personalCommissionPageInfo);
            businessCommissionDetailList.setTemporaryCode(detailListSearchDTO.getTemporaryCode());
            return businessCommissionDetailList;
        }
        return null;
    }

    private String getMaxClearDate(List<String> clearDateStrList) {
        String max = "";
        if (clearDateStrList.size() > 1) {
            for (String cleDateStr : clearDateStrList) {
                int compareTo = max.compareTo(cleDateStr);
                if (compareTo <= 0) {
                    max = cleDateStr;
                }
            }
        } else {
            max = clearDateStrList.get(0);
        }
        return max;
    }

    private void convertType2Name(PageInfo<BusinessCommissionDetailVoV2> personalCommissionPageInfo) {
        List<BusinessCommissionDetailVoV2> dataList = personalCommissionPageInfo.getList();
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }
        List<Long> customerIdList = dataList.stream().map(BusinessCommissionDetailVoV2::getCustomerId).distinct().collect(Collectors.toList());
        Map<Long, BaseCustomer> customerMapping = Objects.requireNonNull(baseInfoClient.getMcnCustomerByIds(customerIdList)).getObj();
        //查询平台名称
        List<Long> starPlatInfoIds = dataList.stream().map(BusinessCommissionDetailVoV2::getStarPlatformInfoId).collect(Collectors.toList());
        Map<Long, StarPlatformInfo> starPlatformInfoMap = CommonUtil.defaultList(starPlatformInfoService.selectBatchIds(starPlatInfoIds))
                .stream().collect(Collectors.toMap(StarPlatformInfo::getId, Function.identity()));

        List<String> brandCodes = dataList.stream().map(BusinessCommissionDetailVoV2::getBrandName).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<String,String> brandMap = brandInfoService.getBrandMapByCodes(brandCodes);
        Map<String, Map<String, String>> secondlevelDictMap = baseInfoClient.getAllSecondlevelDictMap(DictTypeCst.PUBLISHING_PLATFORM);
        dataList.forEach(x -> {
            if (starPlatformInfoMap.containsKey(x.getStarPlatformInfoId())) {
                StarPlatformInfo starPlatformInfo = starPlatformInfoMap.get(x.getStarPlatformInfoId());
                x.setPlatformName(starPlatformInfo.getPlatformName());
                if (StringUtils.isNotBlank(x.getPublishForm())) {
                    x.setPublishFormName(CommonUtil.getMapValue(secondlevelDictMap.get(starPlatformInfo.getPlatformId()), x.getPublishForm()));
                }
            }
            if(brandMap.containsKey(x.getBrandName())) {
                x.setBrandName(brandMap.get(x.getBrandName()));
            }
            if(CommonUtil.containsKey(customerMapping, x.getCustomerId())) {
                x.setCustomerName(customerMapping.get(x.getCustomerId()).getCustomerNameC());
            }
        });
    }

    /**
     * 临时表编号赋值
     *
     * @param code {@link String}
     * @return {@link String}
     */
    public String temporaryCode(String code) {
        String temporaryCode;
        if (StringUtils.isNotBlank(code)) {
            temporaryCode = code;
        } else {
            temporaryCode = CodeGenerateHelper.getCode(BillCodeCst.BUSINESS_COMMISSION);
            temporaryMapper.updateByNoStrategy(Wrappers.<BusinessCommissionDetailTemporary>lambdaUpdate()
                    .set(BusinessCommissionDetailTemporary::getIsDelete, NumberCst.ONE)
                    .eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE)
                    .eq(BusinessCommissionDetailTemporary::getIsSave, Boolean.FALSE));
        }
        return temporaryCode;
    }

    /**
     * 添加合同（全选并确认）
     *
     * @param allContract {@link IncomeContractSearchDTO}
     * @return {@link String}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String selectAllAndConfirm(ExcutionOrderSearchDTO allContract) {
        String temporaryCode = temporaryCode(allContract.getTemporaryCode());
        McnPage<ExcutionOrderVO> mcnPage = new McnPage<ExcutionOrderVO>();
        mcnPage.setPageSize(Integer.MAX_VALUE);
        allContract.setPageSize(10000L);
        List<ExcutionOrderVO> allOrders = contractExcutionOrderService.getAePage(mcnPage, allContract).getRecords();
        if (CollectionUtils.isNotEmpty(allOrders)) {
            List<Long> allExcuteId = allOrders.stream().map(ExcutionOrderVO::getId).collect(Collectors.toList());
            if (Objects.isNull(allContract.getBusinessId())) {
                add(allExcuteId, temporaryCode);
            } else {
                BusinessCommission businessCommission = businessCommissionMapper.selectById(allContract.getBusinessId());
                getIncomeCodesV2(businessCommission, allExcuteId);
                contractExcutionOrderService.updateBusinessCommissionSettleStatusByIds(allExcuteId, NumberCst.ZERO, NumberCst.ONE);
            }
        }
        return temporaryCode;
    }

    /**
     * 切换季度
     *
     * @param quarterCode   季度编号
     * @param temporaryCode 临时表编号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void switchQuarter(String quarterCode, String temporaryCode) {
        List<BusinessCommissionDetailTemporary> list = this.baseMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class).eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE).eq(BusinessCommissionDetailTemporary::getTemporaryCode, temporaryCode));
        if (Objects.nonNull(list) && list.size() > 0) {
            list.forEach(x -> {
                IncomeContract incomeContract = incomeContractMapper.selectById(x.getIncomeId());
                CustomerTarget customerTarget = customerTargetMapper.selectOne(Wrappers.lambdaQuery(CustomerTarget.class).eq(CustomerTarget::getIsDelete, false)
                        .eq(CustomerTarget::getQuarterCode, quarterCode).eq(CustomerTarget::getTargetCustomerId, x.getCustomerId()));
                x.setKeyCustomers(Objects.nonNull(customerTarget) ? NumberCst.ZERO : NumberCst.ONE);
                if (Objects.nonNull(customerTarget)) {
                    if (Objects.nonNull(customerTarget.getTargetReachRate())) {
                        x.setTargetAchievementRate(customerTarget.getTargetReachRate());
                    } else {
                        x.setTargetAchievementRate(BigDecimal.ZERO);
                    }
                } else {
                    x.setTargetAchievementRate(BigDecimal.ONE);
                }
                BigDecimal personalCommission = x.getProjectSales().multiply(x.getGeneralPoints()).multiply(x.getTargetAchievementRate()).setScale(2, BigDecimal.ROUND_HALF_UP);
                x.setPersonalCommission(personalCommission);
                DepartmentTarget departmentTarget = departmentTargetMapper.selectOne(Wrappers.lambdaQuery(DepartmentTarget.class).eq(DepartmentTarget::getIsDelete, false)
                        .eq(DepartmentTarget::getQuarterCode, quarterCode).eq(DepartmentTarget::getTargetDepartmentId, incomeContract.getDepartmentId()));
                if (Objects.nonNull(departmentTarget) && Objects.nonNull(departmentTarget.getTargetReachRate())) {
                    x.setDepartmentTargetAchievementRate(departmentTarget.getTargetReachRate());
                } else {
                    x.setDepartmentTargetAchievementRate(BigDecimal.ZERO);
                }
                this.baseMapper.updateById(x);
            });
        }
    }

    @Override
    public BusinessBoxList getCommissionList(String temporaryCode) {
        if (Objects.nonNull(temporaryCode)) {
            List<BusinessCommissionDetailTemporary> detailTemporaries = temporaryMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetailTemporary.class)
                    .eq(BusinessCommissionDetailTemporary::getTemporaryCode, temporaryCode)
                    .eq(BusinessCommissionDetailTemporary::getIsDelete, Boolean.FALSE));
            List<String> commissionList = detailTemporaries.stream().map(BusinessCommissionDetailTemporary::getCommissionName).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
            List<String> departmentHeaderList = detailTemporaries.stream().map(BusinessCommissionDetailTemporary::getDepartmentHeadName).filter(StringUtils::isNotBlank).distinct().collect(Collectors.toList());
            BusinessBoxList businessBoxList = new BusinessBoxList();
            businessBoxList.setCommissionList(commissionList);
            businessBoxList.setDepartmentHeaderList(departmentHeaderList);
            return businessBoxList;
        }
        return new BusinessBoxList();
    }

    private void getIncomeCodesV2(BusinessCommission businessCommission, List<Long> excuteIds) {
        List<BusinessCommissionDetail> details = businessCommissionDetailMapper.selectList(Wrappers.lambdaQuery(BusinessCommissionDetail.class)
                .eq(BusinessCommissionDetail::getBusinessId, businessCommission.getId())
                .eq(BusinessCommissionDetail::getIsDelete, Boolean.FALSE));
        List<Long> oldExcuteIds = details.stream().filter(x -> Objects.nonNull(x.getExcuteId())).map(BusinessCommissionDetail::getExcuteId).collect(Collectors.toList());
        List<Long> newExcuteIds;

        if (excuteIds.size() > 0) {
            if (oldExcuteIds.size() == 0) {
                newExcuteIds = excuteIds;
            } else {
                newExcuteIds = excuteIds.stream().filter(x -> !oldExcuteIds.contains(x)).collect(Collectors.toList());
            }
            if (newExcuteIds.size() == 0) {
                throw new BusinessException(McnErrorCode.EXCUTE_ORDER_CANNOT_BE_REPEATED);
            }
            //根据执行单ID获取对应的合同号
            List<BusinessCommissionDetailTemporary> tempList = this.executeNewBusinessCommissionRule(businessCommission.getBusinessCommissionCode(), newExcuteIds);
            if (CollectionUtils.isNotEmpty(tempList)) {
                List<BusinessCommissionDetail> detailList = tempList.stream().map(temporary -> {
                    BusinessCommissionDetail detail = new BusinessCommissionDetail();
                    BeanUtils.copyProperties(temporary, detail);
                    detail.setBusinessId(businessCommission.getId());
                    detail.setIsConfirmed(NumberCst.ZERO);
                    detail.setIsInvalid(NumberCst.ZERO);
                    detail.setIsDelete(NumberCst.ZERO);
                    return detail;
                }).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(detailList)) {
                    businessCommissionService.saveBusinessDetails(businessCommission, detailList);
                }
            }
        }
    }

    /**
     * 新的执行商务提成规则
     * @param temporaryCode
     * @param excuteIds
     * @return
     */
    private List<BusinessCommissionDetailTemporary> executeNewBusinessCommissionRule(String temporaryCode, List<Long> excuteIds) {
        List<CommissionContractExcutionOrderVO> excutionOrderVOList = contractExcutionOrderMapper.selectCommissionContractExcutionOrderByIds(excuteIds);
        if(CollectionUtils.isNotEmpty(excutionOrderVOList)) {
            List<BusinessCommissionDetailTemporary> tempList = new ArrayList<>();
            List<Long> ownerIds = excutionOrderVOList.stream().map(CommissionContractExcutionOrderVO::getOwnerId).distinct().collect(Collectors.toList());
            List<Long> userIds = new NoRepeatableArrayList<>(ownerIds);
            List<Long> performanceSharerIds = excutionOrderVOList.stream().filter(e -> Objects.nonNull(e.getPerformanceSharerId()))
                    .map(CommissionContractExcutionOrderVO::getPerformanceSharerId).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(performanceSharerIds)) {
                userIds.addAll(performanceSharerIds);
            }
            List<Long> departmentHeaderIdIds = excutionOrderVOList.stream().filter(e -> Objects.nonNull(e.getContractDepartmentHeaderId()))
                    .map(CommissionContractExcutionOrderVO::getContractDepartmentHeaderId).distinct().collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(departmentHeaderIdIds)) {
                userIds.addAll(departmentHeaderIdIds);
            }
            List<SUser> sUsers = Objects.requireNonNull(privilegeClient.getUserByIds(userIds)).getObj();
            Map<Long, SUser> sUserMap = sUsers.stream().collect(Collectors.toMap(SUser::getUserId, sUser -> sUser));
            Map<Long, DepartmentVO> departmentVoMap = Objects.requireNonNull(privilegeClient.getDepartmentHeadByUserIds(userIds)).getObj();
            for(CommissionContractExcutionOrderVO x : excutionOrderVOList) {
                BusinessCommissionDetailTemporary temporary = new BusinessCommissionDetailTemporary();
                temporary.setExcuteId(x.getId());
                temporary.setExcuteCode(x.getExcuteCode());
                temporary.setIncomeCode(x.getIncomeContractCode());
                temporary.setIncomeId(x.getIncomeContractId());
                temporary.setCustomerId(x.getCustomerId());
                temporary.setBusinessAmount(x.getActualQuotedPrice());
                temporary.setPayBackStatus(x.getPaybackStatus());
                temporary.setCommissionId(x.getOwnerId());
                temporary.setCommissionName(x.getOwnerName());
                temporary.setCreateDate(x.getCreateDate());
                temporary.setCreateBy(UserVoContextHolder.getUserId());
                temporary.setIsDelete(DeleteEnum.FALSE.getValue());
                temporary.setIsSave(NumberCst.ZERO);
                temporary.setIsInvalid(NumberCst.ZERO);
                temporary.setTemporaryCode(temporaryCode);
                if (CommonUtil.containsKey(sUserMap, temporary.getCommissionId())) {
                    temporary.setJobNumber(sUserMap.get(temporary.getCommissionId()).getJobNumber());
                }
                temporary.setDepartmentHeadId(x.getContractDepartmentHeaderId());
                temporary.setDepartmentHeadName(x.getContractDepartmentHeaderName());
                if (MapUtils.isNotEmpty(departmentVoMap)) {
                    DepartmentVO departmentVO = departmentVoMap.get(x.getOwnerId());
                    Long backupDepartmentHeadId = departmentVO != null ? departmentVO.getDepartmentHeadId() : null;
                    String backupDepartmentHeadName = departmentVO != null ? departmentVO.getDepartmentHeadName() : null;
                    temporary.setDepartmentHeadId(Objects.nonNull(temporary.getDepartmentHeadId()) ? temporary.getDepartmentHeadId() : backupDepartmentHeadId);
                    temporary.setDepartmentHeadName(StringUtils.isNotBlank(temporary.getDepartmentHeadName()) ? temporary.getDepartmentHeadName() : backupDepartmentHeadName);
                }
                if(CommonUtil.containsKey(sUserMap, temporary.getDepartmentHeadId())) {
                    temporary.setDepartmentJobNumber(sUserMap.get(temporary.getDepartmentHeadId()).getJobNumber());
                }
                tempList.add(temporary);
                //业绩共享人
                if (NumberCst.ONE.equals(x.getPerformanceShare())) {
                    BusinessCommissionDetailTemporary sharerTemporary = new BusinessCommissionDetailTemporary();
                    BeanUtils.copyProperties(temporary, sharerTemporary);
                    sharerTemporary.setCommissionId(x.getPerformanceSharerId());
                    sharerTemporary.setCommissionName(x.getPerformanceSharerName());
                    if (CommonUtil.containsKey(sUserMap, sharerTemporary.getCommissionId())) {
                        sharerTemporary.setJobNumber(sUserMap.get(sharerTemporary.getCommissionId()).getJobNumber());
                    }
                    tempList.add(sharerTemporary);
                }
            }

            return tempList;
        }
        return null;
    }


    /**
     * 执行商务提成规则
     *
     * @param incomeContracts
     */
    @Deprecated
    @SneakyThrows
    @Override
    public List<BusinessCommissionDetailTemporary> executeBusinessCommissionRule(String temporaryCode, List<QuarterIncomeContractVO> incomeContracts) {
        if (CollectionUtils.isEmpty(incomeContracts)) {
            return null;
        }
        List<Long> departmentIds = new ArrayList<>();
        List<String> quarterCodeList = new ArrayList(1);
        List<Long> customerIds = new ArrayList<>(incomeContracts.size());
        List<Long> ownerIds = new ArrayList(incomeContracts.size());
        List<Long> allUserIds = new ArrayList<>();
        refactor(incomeContracts, departmentIds, quarterCodeList, customerIds, ownerIds, allUserIds);
        Map<Long, BaseCustomer> customerMap = Objects.requireNonNull(baseInfoClient.getMcnCustomerByIds(customerIds)).getObj();
        Map<Long, DepartmentVO> departmentVoMap = Objects.requireNonNull(privilegeClient.getDepartmentHeadByUserIds(ownerIds)).getObj();
        if (departmentVoMap != null && departmentVoMap.size() > 0) {
            for (Map.Entry<Long, DepartmentVO> entry : departmentVoMap.entrySet()) {
                DepartmentVO departmentVO = entry.getValue();
                if (departmentVO.getDepartmentHeadId() == null) {
                    continue;
                }
                if (!allUserIds.contains(departmentVO.getDepartmentHeadId())) {
                    allUserIds.add(departmentVO.getDepartmentHeadId());
                }
            }
        }
        List<SUser> sUsers = Objects.requireNonNull(privilegeClient.getUserByIds(allUserIds)).getObj();
        Map<Long, SUser> sUserMap = sUsers.stream().collect(Collectors.toMap(SUser::getUserId, sUser -> sUser));
        List<DepartmentTarget> departmentTargets = departmentTargetMapper.selectList(Wrappers.lambdaQuery(DepartmentTarget.class).eq(DepartmentTarget::getIsDelete, false)
                .in(DepartmentTarget::getQuarterCode, quarterCodeList).in(DepartmentTarget::getTargetDepartmentId, departmentIds));

        List<CustomerTarget> customerTargets = customerTargetMapper.selectList(Wrappers.lambdaQuery(CustomerTarget.class).eq(CustomerTarget::getIsDelete, false)
                .in(CustomerTarget::getQuarterCode, quarterCodeList).in(CustomerTarget::getTargetCustomerId, customerIds));
        BusinessCommissionRuleContext context = new BusinessCommissionRuleContext(temporaryCode, customerMap, departmentVoMap, sUserMap, departmentTargets, customerTargets);
        Map<String, BusinessCommissionReturn> returnMap = new ConcurrentHashMap<>(incomeContracts.size());
        final Date v2StartDate = DateUtils.parseDate(earliestStartDateStr, McnConstant.LONG_DATE_FORMAT);
        List<BusinessCommissionDetailTemporary> list = new ArrayList<>();
        try {
            incomeContracts.forEach(x -> {
                if (x.getCreateDate().before(v2StartDate)) {
                    context.setQuarterIncomeContractVO(x);
                    list.addAll(ComputableRuleEngine.fire(BusinessCommissionV1Rule.class, context));
                } else {
                    String key = StringUtils.joinWith("_", x.getTenantId(), x.getCompanyId(), x.getDepartmentId(), x.getQuarterCode());
                    if (!returnMap.containsKey(key)) {
                        BusinessCommissionReturn bcReturn = bcReturnMapper.selectOne(Wrappers.lambdaQuery(BusinessCommissionReturn.class)
                                .eq(BusinessCommissionReturn::getTenantId, x.getTenantId())
                                .eq(BusinessCommissionReturn::getCompanyId, x.getCompanyId())
                                .eq(BusinessCommissionReturn::getDepartmentId, x.getDepartmentId())
                                .eq(BusinessCommissionReturn::getQuarterCode, x.getQuarterCode())
                        );
                        if (bcReturn != null) {
                            returnMap.put(key, bcReturn);
                        }
                    }
                    BusinessCommissionReturn bcReturn = returnMap.get(key);
                    x.setReturnRate(Objects.nonNull(bcReturn) ? bcReturn.getReturnRate() : BigDecimal.ONE);
                    x.setReturnFactor(Objects.nonNull(bcReturn) ? bcReturn.getReturnFactor() : BigDecimal.ONE);
                    context.setQuarterIncomeContractVO(x);
                    list.addAll(ComputableRuleEngine.fire(BusinessCommissionV2Rule.class, context));
                }
            });
            return list;
        } finally {
            returnMap.clear();
            context.clear();
        }
    }

    private void refactor(List<QuarterIncomeContractVO> incomeContracts, List<Long> departmentIds, List<String> quarterCodeList, List<Long> customerIds, List<Long> ownerIds, List<Long> allUserIds) {
        incomeContracts.forEach(x -> {
            x.setOperatorId(UserVoContextHolder.getUserId());
            x.setOperatorName(UserVoContextHolder.getUserName());
            if (!customerIds.contains(x.getCustomerId())) {
                customerIds.add(x.getCustomerId());
            }
            if (!ownerIds.contains(x.getOwnerId())) {
                ownerIds.add(x.getOwnerId());
            }
            if (!allUserIds.contains(x.getOwnerId())) {
                allUserIds.add(x.getOwnerId());
            }
            if (!allUserIds.contains(x.getDepartmentHeaderId()) && Objects.nonNull(x.getDepartmentHeaderId())) {
                allUserIds.add(x.getDepartmentHeaderId());
            }
            if (!allUserIds.contains(x.getPerformanceSharerId()) && Objects.nonNull(x.getPerformanceSharerId())) {
                allUserIds.add(x.getPerformanceSharerId());
            }
            if (!departmentIds.contains(x.getDepartmentId()) && Objects.nonNull(x.getDepartmentId())) {
                departmentIds.add(x.getDepartmentId());
            }
            if (!quarterCodeList.contains(x.getQuarterCode()) && Objects.nonNull(x.getQuarterCode())) {
                quarterCodeList.add(x.getQuarterCode());
            }
        });
    }
}
